package org.budo.compress.sevenzip;

import java.io.File;
import java.io.RandomAccessFile;

import org.budo.compress.AbstractCompressor;
import org.budo.support.lang.util.ArrayUtil;
import org.budo.support.lang.util.IoUtil;

import net.sf.sevenzipjbinding.ExtractAskMode;
import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.ISequentialOutStream;
import net.sf.sevenzipjbinding.PropID;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;

/**
 * @author limingwei
 *         http://sevenzipjbind.sourceforge.net/compression_snippets.html
 */
public class SevenzipCompressor extends AbstractCompressor {
    @Override
    public void compress(File from, File to) {
        throw new RuntimeException();
    }

    @Override
    public void decompress(File from, final File to) {
        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile(from, "rw");
            RandomAccessFileInStream inStream = new RandomAccessFileInStream(randomAccessFile);

            final IInArchive inArchive = SevenZip.openInArchive(null, inStream);

            int[] indices = ArrayUtil.sequence_2(0, inArchive.getNumberOfItems() - 1);

            inArchive.extract(indices, false, new AbstractIArchiveExtractCallback() {
                @Override
                public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException {
                    final String path = ((String) inArchive.getProperty(index, PropID.PATH));
                    final boolean isFolder = (Boolean) inArchive.getProperty(index, PropID.IS_FOLDER);
                    return new ISequentialOutStream() {
                        public int write(byte[] data) throws SevenZipException {
                            if (!isFolder) {
                                IoUtil.write(data, new File(to, path));
                            }
                            return data.length;
                        }
                    };
                }
            });
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }
}